package com.stox.client.ui.javafx.chartingy.view;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.input.MouseEvent;
import javafx.stage.Screen;

import com.stox.client.core.model.intf.Navigable;
import com.stox.client.ui.javafx.chartingy.model.chart.Chart;
import com.stox.client.ui.javafx.chartingy.model.plot.PricePlot;
import com.stox.client.workbench.ui.javafx.stage.StoxStage;
import com.stox.shared.model.Bar;
import com.stox.shared.model.Scrip;
import com.stox.shared.model.intf.HasScrip;

public class ChartingViewDisplayHelper {

	private final List<ChartingView> views = new ArrayList<>();
	private ChartingView lastSelectedChartingView;
	private final EventHandler<MouseEvent> viewSelectionEventHandler = new EventHandler<MouseEvent>() {
		@Override
		public void handle(final MouseEvent event) {
			lastSelectedChartingView = (ChartingView) event.getSource();
		}
	};
	private final ChangeListener<Boolean> viewVisibilityChangeListener = new ChangeListener<Boolean>() {
		@Override
		public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue, final Boolean newValue) {
			if ((null != lastSelectedChartingView) && !lastSelectedChartingView.isVisible()) {
				lastSelectedChartingView = null;
			}
			final Iterator<ChartingView> chartingViewIterator = views.iterator();
			while (chartingViewIterator.hasNext()) {
				final ChartingView chartingView = chartingViewIterator.next();
				if (!chartingView.isVisible()) {
					chartingViewIterator.remove();
				}
			}
		}
	};

	@SuppressWarnings("unchecked")
	public void single(final Navigable<? extends HasScrip> navigable) {
		final ChartingView chartingView = getOrCreateLastSelectedChartingView();
		chartingView.setNavigable((Navigable<HasScrip>) navigable);

		final List<? extends HasScrip> hasScrips = navigable.currentAllSelection();
		if ((null != hasScrips) && !hasScrips.isEmpty()) {
			final Chart<Scrip, Bar> chart = chartingView.getPrimaryChart();
			for (int index = 0; index < hasScrips.size(); index++) {
				final HasScrip hasScrip = hasScrips.get(index);
				if ((null != hasScrip) && (null != hasScrip.getScrip())) {
					final Scrip scrip = hasScrip.getScrip();
					final PricePlot plot = new PricePlot();
					if (0 == index) {
						chart.setPrimaryPlot(plot);
					} else {
						chart.getPlots().add(plot);
					}
					plot.setExtraValue(scrip);
				}
			}
			chartingView.open();
			chartingView.getPrimaryChart().getPrimaryPlot().load();
			resizeRelocateAll();
		}
	}

	@SuppressWarnings("unchecked")
	public void multiple(final Navigable<? extends HasScrip> navigable) {
		final List<? extends HasScrip> hasScrips = navigable.currentAllSelection();
		if ((null != hasScrips) && !hasScrips.isEmpty()) {
			for (int index = 0; index < hasScrips.size(); index++) {
				final HasScrip hasScrip = hasScrips.get(index);
				if ((null != hasScrip) && (null != hasScrip.getScrip())) {
					final Scrip scrip = hasScrip.getScrip();
					final ChartingView chartingView = createChartingView();
					chartingView.setNavigable((Navigable<HasScrip>) navigable);
					final PricePlot plot = new PricePlot();
					chartingView.getPrimaryChart().setPrimaryPlot(plot);
					chartingView.open();
					plot.setExtraValue(scrip);
					plot.load();
				}
			}
			resizeRelocateAll();
		}
	}

	private ChartingView createChartingView() {
		final ChartingView view = new ChartingView();
		views.add(view);
		view.addEventFilter(MouseEvent.MOUSE_PRESSED, viewSelectionEventHandler);
		view.visibleProperty().addListener(viewVisibilityChangeListener);
		return view;
	}

	private ChartingView getOrCreateLastSelectedChartingView() {
		if (null == lastSelectedChartingView) {
			if (views.isEmpty()) {
				return createChartingView();
			}
			lastSelectedChartingView = views.get(views.size() - 1);
		}
		return lastSelectedChartingView;
	}

	public void resizeRelocateAll() {
		final int count = views.size();
		int rows = 1;
		int columns = 1;

		while ((rows * columns) < count) {
			rows++;
			if ((rows * columns) < count) {
				columns++;
			}
		}

		for (int i = 0; i < count; i++) {
			final ChartingView chartingView = views.get(i);
			resize(chartingView, count, i + 1, rows, columns);
			relocate(chartingView, count, i + 1, rows, columns);
		}
	}


	private void resize(final ChartingView view, final int count, final int index, final int rows, final int columns) {
		double width = StoxStage.getInstance().getContentPane().getWidth();
		double height = StoxStage.getInstance().getContentPane().getHeight();
		height = 1 == count ? height / 2 : height;
		final double x = Screen.getPrimary().getVisualBounds().getWidth() / 5;
		if (x < (width / 2)) {
			width -= x;
		}

		height = height / rows;
		width = width / columns;
		if (index == count) {
			width += ((rows * columns) - index) * width;
		}
		view.setPrefWidth(width);
		view.setPrefHeight(height);
	}

	private void relocate(final ChartingView view, final int count, final int index, final int rows, final int columns) {
		final double x = Screen.getPrimary().getVisualBounds().getWidth() / 5;
		final double y = StoxStage.getInstance().getContentPane().getLayoutBounds().getMinY();
		double width = StoxStage.getInstance().getContentPane().getWidth() - x;
		double height = StoxStage.getInstance().getContentPane().getHeight();
		height = 1 == count ? height / 2 : height;

		height = height / rows;
		width = width / columns;

		int row = 1;
		int column = 1;
		int counter = 1;
		boolean shouldBreak = false;
		for (int i = 1; i <= rows; i++) {
			for (int j = 1; j <= columns; j++) {
				if (counter == index) {
					row = i;
					column = j;
					shouldBreak = true;
					break;
				}
				counter++;
			}
			if (shouldBreak) {
				break;
			}
		}

		view.setLayoutX(x + ((column - 1) * width));
		view.setLayoutY(y + ((row - 1) * height));
	}

}
